package com.zwps.common.controller.shiro.realm;

import com.zwps.common.core.context.LoginedMarkContext;
import org.apache.shiro.SecurityUtils;
import org.apache.shiro.authc.AuthenticationInfo;
import org.apache.shiro.authc.AuthenticationToken;
import org.apache.shiro.authc.SimpleAuthenticationInfo;
import org.apache.shiro.authz.AuthorizationInfo;
import org.apache.shiro.cas.CasAuthenticationException;
import org.apache.shiro.cas.CasFilter;
import org.apache.shiro.cas.CasRealm;
import org.apache.shiro.cas.CasToken;
import org.apache.shiro.subject.PrincipalCollection;
import org.apache.shiro.subject.SimplePrincipalCollection;
import org.apache.shiro.util.CollectionUtils;
import org.apache.shiro.util.StringUtils;
import org.apache.shiro.web.subject.WebSubject;
import org.jasig.cas.client.authentication.AttributePrincipal;
import org.jasig.cas.client.validation.Assertion;
import org.jasig.cas.client.validation.TicketValidationException;
import org.jasig.cas.client.validation.TicketValidator;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;

import javax.annotation.PostConstruct;
import javax.servlet.http.HttpServletRequest;
import java.util.HashMap;
import java.util.List;

public class ShiroCasRealm extends CasRealm {

    private String casServerUrlPrefix;
    private String casService;

    @Autowired
    private CasFilter casFilter;

    @Value("${application.cas.redirectUrl}")
    private  String redirectUrl;

    public ShiroCasRealm(String casServerUrlPrefix, String casService) {
        this.casServerUrlPrefix = casServerUrlPrefix;
        this.casService = casService;
    }

    @PostConstruct
    public void initProperty(){
//      setDefaultRoles("ROLE_USER");
        setCasServerUrlPrefix(casServerUrlPrefix);
        // 客户端回调地址
        setCasService(casService + "/cas/login");
    }
    @Override
    protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principals) {
        // 没有权限验证体系，所以直接返回
        return super.doGetAuthorizationInfo(principals);
    }

    @Override
    protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken token)  {
        CasToken casToken = (CasToken) token;

        // token为空直接返回，页面会重定向到 Cas Server 登录页，并且携带本项目回调页
        if (token == null) {
            return null;
        }

        // 获取服务端范围的票根
        String ticket = (String) casToken.getCredentials();

        // 票根为空直接返回，页面会重定向到 Cas Server 登录页，并且携带本项目回调页
        if (!StringUtils.hasText(ticket)) {
            return null;
        }

        TicketValidator ticketValidator = ensureTicketValidator();

        try {
            // 票根验证
            Assertion casAssertion = ticketValidator.validate(ticket, getCasService());
            // 获取服务端返回的用户数据
            AttributePrincipal casPrincipal = casAssertion.getPrincipal();

            // 拿到用户唯一标识
            String userId = casPrincipal.getName();


            // 将获取到的本项目数据库用户包装为 shiro 自身的 principal 存于当前 session 中
            // 之后在整个项目中都可以通过 SecurityUtils.getSubject().getPrincipal() 直接获取到当前用户信息
            List<Object> principals = CollectionUtils.asList(casPrincipal.getAttributes());
            PrincipalCollection principalCollection = new SimplePrincipalCollection(principals, getName());
            LoginedMarkContext.login();
            HashMap<String, String> map =  (HashMap) principals.get(0);

            HttpServletRequest request = (HttpServletRequest) ((WebSubject) SecurityUtils.getSubject()).getServletRequest();
            request.setAttribute("cToken", map.get("cToken"));

            casFilter.setSuccessUrl(redirectUrl + map.get("cToken"));
            return new SimpleAuthenticationInfo(principalCollection, ticket);
        } catch (TicketValidationException e) {
            throw new CasAuthenticationException("Unable to validate ticket [" + ticket + "]", e);
        }
    }
}
